/* incoming osc message are forwarded to the oscEvent method. */
//if(theOscMessage.checkAddrPattern("/test")==true) {...}

String addr="";
String statMsg="";
String HUDMsg="";
int savedFlowerState=0;
float[] ranges = new float[8];
boolean sendHUD=false;
int repeatAllMsgs=3;
int msgRepeatDelay=2;

float oscFloatFetch (OscMessage theOscMessage, int which) {
  float theValue=theOscMessage.get(which).floatValue();
  return theValue;
}
void SendMSG(int channel, OscMessage theMsg, boolean override) {
  int trips;
  if (override) {
    trips=1;
  }
  else {
    trips=repeatAllMsgs;
  }
  for (int i = 0; i< trips;i++) {
    switch (channel) {
    case 0:
      oscP5Echo.send(theMsg, AddPad);
      break;
    case 1:
      oscP5Multi.send(theMsg);
      break;
    }
    delay(msgRepeatDelay);
  }
}
void oscEcho(int action, int actInt, float actFlo) {
  int oscIndex=actInt+1;

  switch(action) {
  case 0:
    statMsg="clear controls";
    println (statMsg);
    ZeroControlVariables();
    //transition selector
    echoMsg.clear();
    echoMsg.setAddrPattern("/MAIN/transition");
    echoMsg.add(0.0);
    echoMsg.add(1.0);
    SendMSG(0, echoMsg, false);
    echoMsg = new OscMessage("/l_facetvspod");
    echoMsg.add("facet");
    SendMSG(0, echoMsg, false);
    Set1DToggle("SelectProgram", true, 1, 16, 0, "", -1, true);
    Set1DToggle("FlowerState", true, 1, 16, 0, "", 0, true);
    Set1DToggle("GoMode", false, 1, 3, 3, "yellow", -1, true);
    Set1DFader("Speed", speedMult, "", true, nf(speedMult, 1, 2));
    GoButton();
    ToggleVS();
    SetRecordMode();
    SetFrameButton();
    break;
  case 1: //FlowerState
    statMsg = "FlowerState: "+binary(FlowerState, 16);
    println(statMsg);
    echoMsg = new OscMessage("/FlowerState/1/"+oscIndex);
    echoMsg.add(actFlo);
    SendMSG(0, echoMsg, false);
    echoMsg = new OscMessage("XX/1/");
    echoMsg.add(statMsg);
    SendMSG(1, echoMsg, false);
    GoButton();
    break;
  case 2: //facetVSpod
    facetVSpod =!facetVSpod;    
    ToggleVS();
    GoButton();
    break;
  case 3: //SelectProgram
    statMsg = "SelectProgram: ";
    println(statMsg);
    Set1DToggle("SelectProgram", true, 1, 16, actInt, "", -1, true);
    GoButton();
    break;
  case 4: //framesel
    break;
  case 5: //tog recmode
    recordMode=!recordMode;
    setFrame=recordMode;
    SetRecordMode();
    SetFrameButton();
    break;
  case 6:  // rotating things
    switch (actInt) {
    case 0: // lock toggle
      rotLoc=!rotLoc;
      rotCTRLs();
      if (goFacet==100) {
        echoMsg=new OscMessage("/PLAN/degree");
      } else {
        echoMsg=new OscMessage("/MAIN/degree");
      }
      echoMsg.add(oscRot);
      SendMSG(0, echoMsg, true);
      echoMsg=new OscMessage("/MAIN/rotLoc");
      echoMsg.add(int(rotLoc));
      SendMSG(0, echoMsg, true);
      break;
    case 1: // limit toggle
      echoMsg=new OscMessage("/MAIN/rotLim");
      echoMsg.add(int(rotLim));
      SendMSG(0, echoMsg, true);
      break;
    case 2: // zero the wheel
      oscRotZero();
      //      FacetAct=true;
      break;

    case 3: 
    case 4: //change values
      //      FacetAct=true;
      if (actInt==4) {
        oscRot=actFlo;
      } else {
        oscRot+=actFlo;
      }

      if (goFacet==100) {
        echoMsg=new OscMessage("/PLAN/degree");
      } else {
        echoMsg=new OscMessage("/MAIN/degree");
      }
      echoMsg.add(oscRot);
      SendMSG(0, echoMsg, true);
      echoMsg=new OscMessage("/MAIN/spinDirect");
      echoMsg.add(oscRot);
      SendMSG(0, echoMsg, true);

      break;
    default:
      break;
    }/* end ection 5 code */
    UpdateSeed(8, oscRot);
  case 7: //ping pong
    SetToggle("PingPong", actInt);
    UpdateSeed(6, actInt);
    break;
  default:
    break;
  }
  echoMsg=new OscMessage("/statMsg");
  echoMsg.add(statMsg);
  SendMSG(0, echoMsg, false);
}

void oscEvent(OscMessage theOscMessage) {
  addr = theOscMessage.addrPattern();
  if (addr.indexOf("XX")!=0&&addr!="") {
    boolean bVal=false;
    int iVal=0;
    float fVal=0;
    print("### received an osc message: "+theOscMessage);
    println(" addrpattern: "+addr);
    println(" typetag: "+theOscMessage.typetag());
    if (theOscMessage.checkTypetag("f")) {
      fVal=oscFloatFetch(theOscMessage, 0);
      iVal= int(fVal);
      bVal = boolean(iVal);
    }

    // Message Routing -----
    // rotations 
    if (addr.indexOf("MAIN/rot")>-1) {
      int code=0; //  lock toggle code default, no reason, something gets to be
      if (addr.indexOf("Loc")>-1) {
        statMsg="toggle rotLoc";
        inRot(theOscMessage, code);
      }
      if (addr.indexOf("Lim")>-1) {
        // ##  later add the check to the facet for rotation limits, make compare
        statMsg="toggle rotLim";
        code=1;
        inRot(theOscMessage, code);
      }      
      if ((addr.indexOf("rotZero")>-1)&&(!rotLoc)) {
        if (!bVal) {
          statMsg="zero rotation";
          code=2;
          inRot(theOscMessage, code);
        }
      }
    }
    /* spin */
    if (addr.indexOf("MAIN/spin")>-1) {
      if (!rotLoc) {
        if (addr.indexOf("Fine")>-1) {
          inSpin(theOscMessage, 3);
        } 
        if (addr.indexOf("Direct")>-1) {        
          inSpin(theOscMessage, 4);
        }
        if (addr.indexOf("Up")>-1)
        {
          if (bVal) {
            inSpin(theOscMessage, 72);
          }
        }
        if (addr.indexOf("Dn")>-1)
          if (bVal) {
            inSpin(theOscMessage, -72);
          }
      }
    }


    /* end rotations */

    if (addr.indexOf("Speed")>-1) {
      inSpeed(fVal);
    }
    if (addr.indexOf("/Update")==0) {
      if (!bVal) {
        statMsg="update program";
        GoLaunch(false);
      }
    }
    if (addr.indexOf("/GO")==0) {
      if (!bVal) {
        statMsg="Launch program";
        GoLaunch(true);
      }
    }
    if (addr.indexOf("GoMode")>-1) {
      inGoMode(addr);
    }
    if (addr.indexOf("RecordMode")>-1) {
      inRecMode(iVal);
    }
    if (addr.indexOf("SetFrame")>-1) {
      if (!bVal) { //use this test to select for button release
        inSetFrame();
      }
    }
    if (addr.indexOf("Frame")>-1) {
      inFrame(addr);
    }
    if (addr.indexOf("SETUP")>-1) {
      if (!bVal) {
        PadSetup();
      }
    }
    if (addr.indexOf("CLEAR")>-1) {
      if (!bVal) {
        oscEcho(0, 0, 0.0);
      }
    }
    if (addr.indexOf("FlowerState")>-1) {
      String buffer[] = split(addr, "/");
      int thisFlower = (int(buffer[3])-1);
      inFlower(thisFlower);
    }
    if (addr.indexOf("SelectProgram")>-1) {
      statMsg="Program ";
      String buffer[] = split(addr, "/");
      int thisButton = int(buffer[3]);  //-1;
      inPSelect(thisButton);
    }
    if (addr.indexOf("PingPong")>-1) {
      inPingPong(iVal);
    }
    if (addr.indexOf("FacetVs")>-1) {
      if (!bVal) { //use this test to select for button release
        oscEcho(2, 0, 0.0);
      }
    }
  }
}

void inPingPong(int setVal) {
  statMsg="toggle ping pong";
  oscEcho(6, setVal, 0.0);
}
void inSpin(OscMessage theOscMessage, int code) {
  float ctrlValue=oscFloatFetch(theOscMessage, 0);
  println("rot value: "+ctrlValue);
  /* the following trap may be a problem. trying to stop the button release
   from the up and down 72 spinners from sending two messages, on the press and release
   think about this..*/
  if (ctrlValue!=0) { 
    if ((code!=3)&&(code!=4)) {
      ctrlValue =code;
      code=3;
    }
    oscEcho(6, code, ctrlValue);
  }
}

void inRot(OscMessage theOscMessage, int code) {
  float ctrlValue=oscFloatFetch(theOscMessage, 0);
  oscEcho(6, code, ctrlValue);
}
void inSpeed(float setValue) {  //.1 to 5
  speedMult=setValue;
  Set1DFader("Speed", setValue, "", true, nf(setValue, 1, 2));
  println("speed value: "+setValue);
  println("str= "+str(setValue));
  UpdateSeed(2, setValue);
}


void inGoMode(String goSel) {
  String buffer[] = split(goSel, "/");
  String theColor="";
  if (goMode!=int(buffer[2])) {
    println("savedFlowerState at start: "+savedFlowerState+" vs "+FlowerState);
    goMode= int(buffer[2]);
    if (savedFlowerState>0) {
      FlowerState=savedFlowerState;
      savedFlowerState=0;
    }

    switch (goMode) {
    case 1: 
      if (!flowerVis) {
        FlowerVis(true);
      }
      statMsg="Direct Connect Mode";
      theColor="red";
      break;
    case 2: 
      if (!flowerVis) {
        FlowerVis(true);
      }
      statMsg="Run Mode";
      theColor="green";
      break;
    case 3: 
      if (flowerVis) {
        FlowerVis(false);
      }
      statMsg="Simulation Mode";
      theColor="yellow";
      savedFlowerState=FlowerState;
      FlowerState=32768;
      UpdateSeed(0, FlowerState);
      break;
    }
    println("savedFlowerState at end: "+savedFlowerState+" vs "+FlowerState);
  } else {
    println("no change");
  }

  Set1DToggle("GoMode", false, 1, 3, goMode, theColor, -1, true);
  oscEcho(100, 0, 0.0);
  GoButton();
}

void inSetFrame() {
}

void inRecMode (int togValue) {
  statMsg="toggle record";
  oscEcho(5, togValue, 0.0);
}

void inFrame (String frameSel) {
  String buffer[] = split(frameSel, "/");
  int thisFrameA = (int(buffer[2])-1);
  int thisFrameB = (int(buffer[3])-1);
  pFrame=thisFrameA*thisFrameB;
  oscEcho(4, pFrame, 1.0);
}

void inFlower(int togIn) {
  statMsg="inFlower";
  boolean thisState = decodeFlowers(togIn);
  int newState=int(!thisState);
  // use the return to toggle the binary value of FlowerState
  if (thisState) { 
    //switch from ON to OFF
    FlowerState-=int(pow(2, float(togIn)));
  } else {
    FlowerState+=int(pow(2, float(togIn)));
  }
  //flip the boolean, int, then float, send to echo for state change
  oscEcho(1, togIn, float(newState));
}

void inPSelect(int togIn) {
  boolean valid=true;
  statMsg="inPSelect";
  if (facetVSpod) {
    if (togIn>=fRows) { //set to >= to convert to zero based array. for pods below, too
      valid=false;
    } else {
      facetSelected=togIn;
      UpdateSeed(1, facetSelected); //only put facet values in seed
    }
  } else {
    if (togIn>=pRows) {
      valid=false;
    } else {
      podSelected=togIn;
    }
  }
  if (valid) {
    oscEcho(3, togIn, 1.0);
  }
}

